package utils

import (
	"errors"
	"goadmin/conf"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

type myClaims struct {
	UserId  uint
	Refresh bool // 是否是刷新token,刷新token只能用于刷新 token,不能用于其他操作
	jwt.RegisteredClaims
}

// 生成jwt
func GenerateToken(userID uint) (accessToken string, refreshToken string, err error) {
	claims := &myClaims{
		userID,
		false,
		jwt.RegisteredClaims{
			Issuer:    conf.Jwt.Issuer,
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(conf.Jwt.Expire) * time.Second)),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	accessToken, err = token.SignedString([]byte(conf.Jwt.Key))
	if err != nil {
		return
	}
	claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Duration(conf.Jwt.RefreshExpireHour) * time.Hour))
	claims.Refresh = true
	refresh := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	refreshToken, err = refresh.SignedString([]byte(conf.Jwt.Key))
	return
}

// 解析refresh token
func ParseRefreshToken(token string) (userID uint, err error) {
	claims, err := parseStr(token)
	if err != nil {
		return
	}
	if !claims.Refresh {
		err = errors.New("invalid refresh token")
		return
	}
	userID = claims.UserId
	return
}

// 解析token
func ParseToken(token string) (userID uint, err error) {
	claims, err := parseStr(token)
	if err != nil {
		return
	}
	if claims.Refresh {
		err = errors.New("invalid access token")
		return
	}
	userID = claims.UserId
	return
}

// 解析jwt
func parseStr(str string) (claims *myClaims, err error) {
	token, err := jwt.ParseWithClaims(str, &myClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(conf.Jwt.Key), nil
	})
	if err != nil {
		return
	}
	if claims, ok := token.Claims.(*myClaims); ok && token.Valid {
		return claims, nil
	} else {
		err = errors.New("invalid token")
	}
	return
}
